#include "stm32f4xx_SSD1289.h"


/* ************************************************************** *
 * ******************* LOCAL FUNCTIONS SECTION ****************** *
 * ************************************************************** */

static void Powersetting_local(void)
{
	/* frame freq = fosc/4 in 256k mode */
	SSD1289_WriteReg(0x0003, 0x06A6);

	/* VCIX2 voltage is 5.1V */
	SSD1289_WriteReg(0x000C, 0x0000);

	/* Amplify Vref by 2.5 (Vref is 2V) */
	SSD1289_WriteReg(0x000D, 0x000C);

	/* Vcom Alternative Amplitude = VLCD63 x 0.99 */
	SSD1289_WriteReg(0x000E, 0x2c00);

	/* VcomH = VLCD63 x 0.99 */
	SSD1289_WriteReg(0x001E, 0x003F);

	/* because VCOML = 0.9475*VCOMH - VCOMA so VCOML will be -0.2626 */

	/* End of SSD1289_Powersetting */
	return;
}




static void FrameFrequency_local(void)
{
	/* RL = 0 and ignored because RAM display mode
	 * REV = 1, reverse data.
	 * CAD = 0, Cs on Common
	 * BGR = 1
	 * TB = 1, image is reversed
	 */
	SSD1289_WriteReg(0x0001, 0x2B3F);


	/* NO1 = 0, NO0 = 1
	 * SDT = 00, EQ = 000, DIV = 0, fosc ~ 510 KHz
	 * SDIV = 1
	 * SRTN = 1,
	 */
	SSD1289_WriteReg(0x000B, 0x4030);

	/* End of SSD1289_FrameFrequency */
	return;
}



static void InternalDisplay_On_local(void)
{
	/* GON =1, DTE = 0, D[1:0] = 01
	 * Source output is GND
	 */
    SSD1289_WriteReg(0x0007, 0x0021);

    /* End of InternalDisplay_On_local */
	return;
}

static void ExternalDisplay_Prepare_local(void)
{
	/* GON =1, DTE = 0, D[1:0] = 11
	 * Grayscale output
	 */
	SSD1289_WriteReg(0x0007, 0x0023);

	 /* End of ExternalDisplay_On_local */
	return;
}

static void Osc_On_local(void)
{
	/* OSCEN = 1 */
	SSD1289_WriteReg(0x0000, 0x0001);

	/* End of Osc_On */
	return;
}

static void Sleepmode_Exit_local(void)
{
	/* SLP = 0 */
	SSD1289_WriteReg(0x0010, 0x0000);
	Delay_ms(50);

	/* End of Sleepmode_Exit */
	return;
}

static void ExternalDisplay_On_local(void)
{
	/* GON = 1, DTE = 1, D[1:0] = 11 */
	SSD1289_WriteReg(0x0007, 0x0033);

	/*End of ExternalDisplay_On_local */
	return;
}

static void EntryModeSettings_local(void)
{
	SSD1289_WriteReg(0x0011, 0x6830);

	/*End of EntryModeSettings */
	return;
}

static void ACSetting_local(void)
{
	/* Line inversion, B/C = 1 , EOR = 1 */
	SSD1289_WriteReg(0x0002, 0x0600);

	/* End of ACSetting */
	return;
}

/* This function is the function to set the horizontal address for internal window, which is used for
 * drawing the smalls images on the background
 */
static void SmallWinH_local(UIN16 Start, UIN16 Height)
{
	/* Initialise the ending address, height is zero */
	UIN16 End = Start;

	/* Pre-process the start address */
	if(Start > Max_Row)
	{
		Start = Max_Row;
		Height = ONE_16;
	}

	/* Because the SSD1289 can handle maximum 320 pixels high so the height must be 320 or less */
	if(Height > 320u)
	{
		Height = 320u;
	}
	else
	{
		/* Do nothing as the heigth is in range */
	}

	/* Calculate the ending row address */
	End = Start + Height - ONE_16;

	if(End > Max_Row)
	{
		End = Max_Row;
	}


	SSD1289_WriteReg(Vertical_RAM_Address_Start, Start);
	SSD1289_WriteReg(Vertical_RAM_Address_End, End);

	return;
}

/* This function is the function to set the horizontal address for internal window, which is used for
 * drawing the small images on the background */
static void SmallWinW_local(UIN16 Start, UIN16 Width)
{
	/* Initialise the ending address, height is zero */
	UIN16 End = Start;

	/* Pre-process the start address */
	if(Start > Max_Col)
	{
		Start = Max_Col;
		Width = ONE_16;
	}

	/* Because the SSD1289 can handle maximum 240 pixels wide so the width must be 240 or less */
	if(Width > Max_Col)
	{
		Width = Max_Col;
	}
	else
	{
		/* Do nothing as the heigth is in range */
	}

	/* Calculate the ending row address */
	End = Start + Width - ONE_16;

	if(End > (Max_Col-ONE_16))
	{
		End = Max_Col-ONE_16;
	}

	/* Create the data to write to register */
	End = (End << ByteShift) | Start;

	SSD1289_WriteReg(Horizontal_RAM_Address, End);


	return;
}
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/



/* This function configures parameters for FSMC interface */
inline void SSD1289_Para_Init(void)
{
    FSMC_NORSRAMInitTypeDef InitStruct;
    FSMC_NORSRAMTimingInitTypeDef TimingInitStruct;

    InitStruct.FSMC_Bank = FSMC_Bank1_NORSRAM1;
    InitStruct.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
    InitStruct.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
    InitStruct.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
    InitStruct.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
    InitStruct.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
    InitStruct.FSMC_WrapMode = FSMC_WrapMode_Disable;
    InitStruct.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
    InitStruct.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
    InitStruct.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
    InitStruct.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
    InitStruct.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
    InitStruct.FSMC_WriteBurst = FSMC_WriteBurst_Disable;//disable
    InitStruct.FSMC_ReadWriteTimingStruct = &TimingInitStruct;

    FSMC_NORSRAMInit(&InitStruct);
    TimingInitStruct.FSMC_AddressSetupTime = 0;    //0
    TimingInitStruct.FSMC_AddressHoldTime = 0;	//0
    TimingInitStruct.FSMC_DataSetupTime = 4;	//3
    TimingInitStruct.FSMC_BusTurnAroundDuration = 0;
    TimingInitStruct.FSMC_CLKDivision = 1;//1
    TimingInitStruct.FSMC_DataLatency = 0;
    TimingInitStruct.FSMC_AccessMode = FSMC_AccessMode_A;
    InitStruct.FSMC_WriteTimingStruct = &TimingInitStruct;
    FSMC_NORSRAMInit(&InitStruct);

    FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);


	/* End of SSD1289_Para_Init function */
	return;
}



/* This function allows writing to SSD1289 register
 * Parameters:
 *  + Address of the register (uint16)
 *  + Content to write to register (uint16)
 */
inline void SSD1289_WriteReg(UIN16 Reg_Add, UIN16 Reg_Value)
{
    *Write_Reg = Reg_Add;
    *Write_RAM = Reg_Value;

	/* End of the function SSD1289_WriteReg */
	return;
}



/* This function allows writing to LCD GRAM
 * Each call will write data to a pixel
 * Parameters:
 *  + Content to write to GRAM (uint16)
 */
inline void SSD1289_WritePixel(UIN16 Pix_Value)
{
	*Write_RAM = Pix_Value;

	/*End of function SSD1289_WritePixel*/
	return;
}

/* This function initialises registers of SSD1289
 * Return type: void
 */
inline void SSD1289_Reg_Init(void)
{
	/* Initialise coordinators to [0,0] */
	SSD1289_WriteReg(0x004e, 0x0000);
	SSD1289_WriteReg(0x004f, 0x0000);
	SSD1289_WriteReg(0x0044, 0xEF00);
	SSD1289_WriteReg(0x0045, 0x0000);
	SSD1289_WriteReg(0x0046, 0x013F);
	SSD1289_WriteReg(0x0023, 0x0000);
	SSD1289_WriteReg(0x0024, 0x0000);


	/* End of SSD1289_LCD_Init */
	return;
}



/* This function initialises the LCD
 * Return type: void
 */
inline void SSD1289_Init(void)
{
	SSD1289_Para_Init();


	/* Power suppy setting */
	Powersetting_local();

	/* Frame frequency */
	FrameFrequency_local();

	/* Turn on internal display, but off gates */
	InternalDisplay_On_local();

	/* Turn on the Osc */
	Osc_On_local();

	/* External display on, prepared */
	ExternalDisplay_Prepare_local();

	/* Exit sleep mode */
	Sleepmode_Exit_local();

	/* External Display On */
	ExternalDisplay_On_local();

	/* Entry mode setting */
	EntryModeSettings_local();

	/* ACSetting */
	ACSetting_local();

	SSD1289_Reg_Init();
	/*End of SSD1289_LCD_Init */
	return;
}


inline void SSD1289_SetWindow(struct LCD_Coord * Pos)
{
	SmallWinH_local(Pos->Y_Add, Pos->Height);
	SmallWinW_local(Pos->X_Add, Pos->Width);
	SSD1289_WriteReg(Entry_Mode, SmallWin);
	SSD1289_WriteReg(X_Address, Pos->X_Add);
	SSD1289_WriteReg(Y_Address, Pos->Y_Add);
	*Write_Reg = 0x0022;
	return;
}

inline void SSD1289_CloseWindow()
{
	SSD1289_WriteReg(Entry_Mode, NormalWin);
	SSD1289_WriteReg(X_Address, ZERO_16);
	SSD1289_WriteReg(X_Address, ZERO_16);
	SSD1289_WriteReg(Horizontal_RAM_Address, 0xEF00);
	SSD1289_WriteReg(Vertical_RAM_Address_Start, 0x0000);
	SSD1289_WriteReg(Vertical_RAM_Address_End, 0x013F);
	*Write_Reg = 0x0022;

	return;
}








